package org.hawk.gwt.ppc.parser.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.hawk.gwt.ppc.parser.CompilationUnitDescriptor;
import org.hawk.gwt.ppc.parser.Descriptor;
import org.hawk.gwt.ppc.parser.ExpressionDescriptor;
import org.hawk.gwt.ppc.parser.Token;

/**
 * General implementation of descriptor methods.
 * 
 * @author alex.bereznevatiy@gmail.com
 *
 */
abstract class AbstractDescriptor implements Descriptor {
	
	private Descriptor parent;
	private CompilationUnitDescriptor compilationUnit;
	private Token first; 
	private Token last;

	AbstractDescriptor(Token first, Token last) {
		this.first = first;
		this.last = last;
	}

	/**
	 * @param list
	 * @return unmodifiable list created based on passed list.
	 * {@link ArrayList} will be trimed to size.
	 */
	static <T> List<T> unmodify(List<T> list) {
		if (list.isEmpty()) {
			return Collections.emptyList();
		}
		if (list instanceof ArrayList) {
			((ArrayList<?>)list).trimToSize();
		}
		return Collections.unmodifiableList(list);
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.Descriptor#getCompilationUnit()
	 */
	public CompilationUnitDescriptor getCompilationUnit() {
		return compilationUnit;
	}
	
	void setCompilationUnit(CompilationUnitDescriptor compilationUnit) {
		this.compilationUnit = compilationUnit;
	}

	/*
	 * Reference to parent container.
	 * Sometimes used by child descriptors.
	 */
	Descriptor getParent() {
		return parent;
	}

	void setParent(Descriptor parent) {
		this.parent = parent;
	}

	/* (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.Descriptor#getFirstToken()
	 */
	public Token getFirstToken() {
		return first;
	}
	
	/**
	 * @return last token belongs to this descriptor
	 */
	public Token getLastToken() {
		return last;
	}
	
	/**
	 * Setys last token to this descriptor.
	 * @param last
	 */
	void setLastToken(Token last) {
		this.last = last;
	}

	/* (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.Descriptor#hasToken(int, int)
	 */
	public boolean hasToken(int line, int offset) {
		Token first = getFirstToken();
		Token last = getLastToken();
		if (first == null || last == null) {
			return false;
		}
		if (line < first.getLine() || 
				(line == first.getLine() && offset < first.getOffset())) {
			return false;
		}
		if (line > last.getLine() || 
				(line == last.getLine() && offset > last.getOffset())) {
			return false;
		}
		return true;
	}
}

/**
 * Represents abstract expression.
 * 
 * @author alex.bereznevatiy@gmail.com
 *
 */
abstract class AbstractExpressionDescriptor extends AbstractDescriptor implements ExpressionDescriptor {
	
	AbstractExpressionDescriptor(Token first, Token last) {
		super(first, last);
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.impl.AbstractDescriptor#getParent()
	 */
	@Override
	public ExpressionDescriptor getParent() {
		Descriptor parent = super.getParent();
		if (parent instanceof ExpressionDescriptor) {
			return (ExpressionDescriptor) parent;
		}
		return null;
	}
}
